import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import matplotlib.pyplot as plt

# 设置中文字体支持
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题


# 实验3.1 搭建Plotly组件环境并画简单三维图形
def plotly_3d_basic():
    """创建简单的3D图形示例"""
    print("\n=== 3.1 简单三维图形可视化 ===")

    # 生成示例数据
    x = np.linspace(-5, 5, 100)
    y = np.linspace(-5, 5, 100)
    x, y = np.meshgrid(x, y)
    z = np.sin(np.sqrt(x ** 2 + y ** 2))

    # 创建3D表面图
    fig = go.Figure(data=[go.Surface(x=x, y=y, z=z)])
    fig.update_layout(
        title='3D表面图示例 - 正弦波',
        scene=dict(
            xaxis_title='X轴',
            yaxis_title='Y轴',
            zaxis_title='Z轴'
        )
    )

    # 显示图形
    fig.show()

    # 生成3D散点图数据
    np.random.seed(42)
    num_points = 100
    x = np.random.randn(num_points)
    y = np.random.randn(num_points)
    z = np.random.randn(num_points)
    colors = np.random.rand(num_points)
    sizes = np.random.rand(num_points) * 50

    # 创建3D散点图
    fig = go.Figure(data=[go.Scatter3d(
        x=x, y=y, z=z,
        mode='markers',
        marker=dict(
            size=sizes,
            color=colors,
            colorscale='Viridis',
            opacity=0.8
        )
    )])

    fig.update_layout(
        title='3D散点图示例',
        scene=dict(
            xaxis_title='X值',
            yaxis_title='Y值',
            zaxis_title='Z值'
        )
    )

    # 显示图形
    fig.show()

    print("简单3D图形可视化完成！")


# 实验3.2 3D图形可视化显示
def plotly_3d_advanced():
    """创建更复杂的3D图形可视化"""
    print("\n=== 3.2 高级3D图形可视化 ===")

    # 加载或创建数据集
    # 使用plotly内置的数据集
    df = px.data.iris()

    # 创建3D散点图，使用不同颜色表示不同类别
    fig = px.scatter_3d(
        df, x='sepal_length', y='sepal_width', z='petal_width',
        color='species',
        size='petal_length',
        size_max=18,
        opacity=0.7,
        title='鸢尾花数据集的3D可视化'
    )

    # 更新布局
    fig.update_layout(
        scene=dict(
            xaxis_title='萼片长度',
            yaxis_title='萼片宽度',
            zaxis_title='花瓣宽度'
        )
    )

    # 显示图形
    fig.show()

    # 创建3D线图 - 螺旋线
    t = np.linspace(0, 10, 1000)
    x = np.cos(t)
    y = np.sin(t)
    z = t

    fig = go.Figure(data=[go.Scatter3d(
        x=x, y=y, z=z,
        mode='lines',
        line=dict(
            color='darkblue',
            width=2
        )
    )])

    fig.update_layout(
        title='3D螺旋线',
        scene=dict(
            xaxis_title='X轴',
            yaxis_title='Y轴',
            zaxis_title='Z轴'
        )
    )

    # 显示图形
    fig.show()

    # 创建3D曲面图 - 高斯分布
    x = np.linspace(-3, 3, 100)
    y = np.linspace(-3, 3, 100)
    x, y = np.meshgrid(x, y)
    z = np.exp(-(x ** 2 + y ** 2))

    fig = go.Figure(data=[go.Surface(
        x=x, y=y, z=z,
        colorscale='Viridis'
    )])

    fig.update_layout(
        title='3D高斯分布曲面',
        scene=dict(
            xaxis_title='X轴',
            yaxis_title='Y轴',
            zaxis_title='Z轴'
        )
    )

    # 显示图形
    fig.show()

    print("高级3D图形可视化完成！")


# 实验3.3 折线图、散点图可视化显示
def plotly_line_scatter():
    """创建折线图和散点图可视化"""
    print("\n=== 3.3 折线图和散点图可视化 ===")

    # 创建时间序列数据
    dates = pd.date_range(start='2023-01-01', periods=100, freq='D')
    values1 = np.random.randn(100).cumsum() + 10
    values2 = np.random.randn(100).cumsum() + 10
    values3 = np.random.randn(100).cumsum() + 10

    # 创建DataFrame
    df = pd.DataFrame({
        '日期': dates,
        '产品A销量': values1,
        '产品B销量': values2,
        '产品C销量': values3
    })

    # 创建折线图
    fig = px.line(
        df, x='日期', y=['产品A销量', '产品B销量', '产品C销量'],
        title='三种产品销量趋势图'
    )

    # 更新布局
    fig.update_layout(
        xaxis_title='日期',
        yaxis_title='销量 (单位:千)',
        legend_title='产品'
    )

    # 显示图形
    fig.show()

    # 创建散点图 - 身高体重关系
    np.random.seed(42)
    n = 100
    height = np.random.normal(170, 10, n)
    weight = 0.7 * height + np.random.normal(0, 10, n)
    age = np.random.randint(20, 60, n)
    gender = np.random.choice(['男', '女'], n)

    df_scatter = pd.DataFrame({
        '身高(cm)': height,
        '体重(kg)': weight,
        '年龄': age,
        '性别': gender
    })

    # 创建散点图
    fig = px.scatter(
        df_scatter, x='身高(cm)', y='体重(kg)',
        color='性别', size='年龄',
        hover_data=['年龄'],
        title='身高与体重关系散点图'
    )

    # 添加最佳拟合线
    fig.update_layout(showlegend=True)

    # 显示图形
    fig.show()

    # 创建多面板图表
    fig = make_subplots(rows=1, cols=2,
                        subplot_titles=('线性关系', '非线性关系'))

    # 添加第一个散点图（线性关系）
    x = np.linspace(0, 10, 100)
    y1 = 2 * x + 3 + np.random.randn(100) * 1.5

    fig.add_trace(
        go.Scatter(x=x, y=y1, mode='markers', name='线性数据'),
        row=1, col=1
    )

    # 添加最佳拟合线
    fig.add_trace(
        go.Scatter(x=x, y=2 * x + 3, mode='lines', name='拟合线', line=dict(color='red')),
        row=1, col=1
    )

    # 添加第二个散点图（非线性关系）
    y2 = x ** 2 + np.random.randn(100) * 5

    fig.add_trace(
        go.Scatter(x=x, y=y2, mode='markers', name='非线性数据'),
        row=1, col=2
    )

    # 添加最佳拟合曲线
    x_fit = np.linspace(0, 10, 100)
    y_fit = x_fit ** 2
    fig.add_trace(
        go.Scatter(x=x_fit, y=y_fit, mode='lines', name='拟合曲线', line=dict(color='red')),
        row=1, col=2
    )

    # 更新布局
    fig.update_layout(
        title='线性与非线性关系对比',
        height=500, width=1000
    )

    # 更新坐标轴标签
    fig.update_xaxes(title_text='X值', row=1, col=1)
    fig.update_yaxes(title_text='Y值', row=1, col=1)
    fig.update_xaxes(title_text='X值', row=1, col=2)
    fig.update_yaxes(title_text='Y值', row=1, col=2)

    # 显示图形
    fig.show()

    print("折线图和散点图可视化完成！")


if __name__ == "__main__":
    print("开始执行实验3：大数据可视化显示\n")

    # 步骤1：简单3D图形
    plotly_3d_basic()

    # 步骤2：高级3D图形
    plotly_3d_advanced()

    # 步骤3：折线图和散点图
    plotly_line_scatter()

    print("\n实验3执行完毕！")